﻿/******
 * 刷新令牌类使用redis 或文件存储key
 * Header        Content-Type: application/x-www-form-urlencoded
 * Request Body  grant_type=refresh_token&refresh_token=refreshtokenid
 * *****/
using aier.wx.nosql.redis;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace aier.wx.api.selfhost
{
    public class StoreRefreshTokenProvider : AuthenticationTokenProvider
    {
        private IRefreshTokenService _refreshTokenService;
        private double expiresSpan = 60;

        public StoreRefreshTokenProvider(IRefreshTokenService refreshTokenService)
        {
            this._refreshTokenService = refreshTokenService;
        }

        public override async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            string refreshTokenId = Guid.NewGuid().ToString("n");
            var refreshToken = new RefreshToken()
            {
                Id = refreshTokenId,
                UserName = context.Ticket.Identity.Name,
                IssuedUtc = DateTime.UtcNow,
                ExpiresUtc = DateTime.UtcNow.AddMinutes(expiresSpan),
                ProtectedTicket = context.SerializeTicket()
            };

            context.Ticket.Properties.IssuedUtc = refreshToken.IssuedUtc;
            context.Ticket.Properties.ExpiresUtc = refreshToken.ExpiresUtc;

            if (await _refreshTokenService.Save(refreshToken, TimeSpan.FromMinutes(expiresSpan)))
            {
                context.SetToken(refreshTokenId);
            }
        }

        public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            var refreshToken = await _refreshTokenService.Get(context.Token);

            if (refreshToken != null)
            {
                context.DeserializeTicket(refreshToken.ProtectedTicket);
                var result = await _refreshTokenService.Remove(context.Token);
            }
        }
    }

    public class RefreshToken
    {
        public string Id { get; set; }

        public string UserName { get; set; }

        public DateTime IssuedUtc { get; set; }

        public DateTime ExpiresUtc { get; set; }

        public string ProtectedTicket { get; set; }
    }

    public interface IRefreshTokenService
    {
        Task<RefreshToken> Get(string Id);
        Task<bool> Save(RefreshToken refreshToken);

        Task<bool> Save(RefreshToken refreshToken, TimeSpan expires);

        Task<bool> Remove(string Id);
    }

    public interface IRefreshTokenRepository
    {
        Task<RefreshToken> FindById(string Id);

        Task<bool> Insert(RefreshToken refreshToken);

        Task<bool> Insert(RefreshToken refreshToken, TimeSpan expires);

        Task<bool> Delete(string Id);
    }

  

    public class RefreshTokenRedisRepository : IRefreshTokenRepository
    {
        private RedisClientManager redisClientManager;
        public RefreshTokenRedisRepository(RedisClientManager redisClientManager)
        {
            this.redisClientManager = redisClientManager;
        }

        public Task<bool> Delete(string Id)
        {
            return Task.Factory.StartNew<bool>(() =>
            {
                return redisClientManager.UseRedisClient<bool>(action => {
                    var refreshTokens = action.As<RefreshToken>();
                     refreshTokens.DeleteById(Id);
                     return true;
                });
            });
        }

        public Task<RefreshToken> FindById(string Id)
        {
            return Task.Factory.StartNew<RefreshToken>(() =>
            {
                return redisClientManager.UseRedisClient<RefreshToken>(action => {
                    var refreshTokens = action.As<RefreshToken>();
                    return refreshTokens.GetById(Id);
                });
            });
           
        }

        public Task<bool> Insert(RefreshToken refreshToken)
        {
            return Task.Factory.StartNew<bool>(() =>
            {
                return redisClientManager.UseRedisClient<bool>(action => {
                    var refreshTokens = action.As<RefreshToken>();
                   return refreshTokens.Store(refreshToken) != null;
                });
            });
        }

        public Task<bool> Insert(RefreshToken refreshToken,TimeSpan expires)
        {
            return Task.Factory.StartNew<bool>(() =>
            {
                return redisClientManager.UseRedisClient<bool>(action => {
                    var refreshTokens = action.As<RefreshToken>();
                    return refreshTokens.Store(refreshToken, expires) != null;
                });
            });
        }
    }


    public class RefreshTokenService : IRefreshTokenService
    {
        private IRefreshTokenRepository _refreshTokenRepository;

        public RefreshTokenService(IRefreshTokenRepository refreshTokenRepository)
        {
            _refreshTokenRepository = refreshTokenRepository;
        }

        public async Task<RefreshToken> Get(string Id)
        {
            return await _refreshTokenRepository.FindById(Id);
        }

        public async Task<bool> Save(RefreshToken refreshToken)
        {
            return await _refreshTokenRepository.Insert(refreshToken);
        }

        public async Task<bool> Remove(string Id)
        {
            return await _refreshTokenRepository.Delete(Id);
        }

        public async Task<bool> Save(RefreshToken refreshToken, TimeSpan expires)
        {
            return await _refreshTokenRepository.Insert(refreshToken, expires);
        }
    }

    //public class RefreshTokenRepository : IRefreshTokenRepository
    //{
    //    private string _jsonFilePath;
    //    private List<RefreshToken> _refreshTokens;

    //    public RefreshTokenRepository()
    //    {
    //        var path  = string.Concat(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase), "/App_Data/RefreshToken.json");
    //        _jsonFilePath = new Uri(path).LocalPath;

    //        if (File.Exists(_jsonFilePath))
    //        {
    //            var json = File.ReadAllText(_jsonFilePath);
    //            _refreshTokens = JsonConvert.DeserializeObject<List<RefreshToken>>(json);

    //        }
    //        if (_refreshTokens == null) _refreshTokens = new List<RefreshToken>();
    //    }

    //    public async Task<RefreshToken> FindById(string Id)
    //    {
    //       return  await Task.Factory.StartNew(() =>
    //        {
    //            return _refreshTokens.Where(x => x.Id == Id).FirstOrDefault();
    //        });
    //    }

    //    public async Task<bool> Insert(RefreshToken refreshToken)
    //    {
    //        _refreshTokens.Add(refreshToken);
    //        await WriteJsonToFile();
    //        return true;
    //    }

    //    public async Task<bool> Delete(string Id)
    //    {
    //        _refreshTokens.RemoveAll(x => x.Id == Id);
    //        await WriteJsonToFile();
    //        return true;
    //    }

    //    private async Task WriteJsonToFile()
    //    {
    //        using (var tw = TextWriter.Synchronized(new StreamWriter(_jsonFilePath, false)))
    //        {
    //            await tw.WriteAsync(JsonConvert.SerializeObject(_refreshTokens, Formatting.Indented));
    //        }
    //    }
    //}
}
